package lock;

import java.util.concurrent.*;

/**
 * 案例：基于信号量Semaphore实现多线程交替打印A B C
 */
public class SemaphoreTest2 {

    public static void main(String[] args) {
        multiThreadPrint(new String[]{"A", "B", "C", "D"}, 1000);
    }

    /**
     * 一劳永逸解决多线程交替打印字符串问题
     * @param strs 需要交替打印的字符串集
     * @param millis 每次打印完等待的时间
     */
    public static void multiThreadPrint(final String[] strs, final long millis) {
        final int n = strs.length;
        Semaphore[] semaphores = new Semaphore[n];
        semaphores[0] = new Semaphore(1);//第一个字符串首次打印不需要阻塞等待
        for (int i = 1;i < n;i++) {
            semaphores[i] = new Semaphore(0);
        }
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(n, n, 0L, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
        for (int i = 0;i < n;i++) {
            final int finalI = i;//Variable used in lambda expression should be final or effectively final
            threadPoolExecutor.execute(() -> {
                //todo java跨线程传递数据的几种方式
                while (true) {
                    try {
                        semaphores[finalI].acquire();//先要获取信号资源才能打印，否则阻塞等待
                        System.out.println(strs[finalI]);
                        Thread.sleep(millis);
                        if (finalI + 1 < n) semaphores[finalI+1].release();//打印完后释放下一个信号资源以唤醒下一个线程进行打印
                        else semaphores[0].release();//最后一个线程打印完后再反过来唤醒第一个线程开启下一轮循环打印
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
        }
        threadPoolExecutor.shutdown();
    }
}
